package com.spider.im.chat.server;

import com.spider.im.chat.message.MessageHandlerContext;
import com.spider.im.common.aspect.BusinessException;
import com.spider.im.common.utils.NetworkUtils;
import com.spider.im.common.utils.SpringContextUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class NettyWebsocketServer {

//    @Value("${netty.port:8090}")
//    private int port;
//
//    @Value("${netty.readerIdleTimeSeconds:600}")
//    private int readerIdleTimeSeconds;
//
//    @Value("${netty.writerIdleTimeSeconds:600}")
//    private int writerIdleTimeSeconds;
//
//    @Value("${netty.allIdleTimeSeconds:3600}")
//    private int allIdleTimeSeconds;

    private static final int PORT = 8090;
    private static final int readerIdleTimeSeconds = 600;
    private static final int writerIdleTimeSeconds = 600;
    private static final int allIdleTimeSeconds = 3600;



    private final AtomicInteger connectionsCount = new AtomicInteger(0);

    public void start()  {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            MessageHandlerContext context = SpringContextUtil.getBean(MessageHandlerContext.class);
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new HttpServerCodec());
                            pipeline.addLast(new HttpObjectAggregator(65536));
                            pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
                            // protobuf codec handlers
//                            pipeline.addLast(new ProtobufVarint32FrameDecoder());
//                            pipeline.addLast(new ProtobufDecoder(ChatProto.MessageWrapper.getDefaultInstance()));
//                            pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
//                            pipeline.addLast(new ProtobufEncoder());

                            pipeline.addLast(new IdleStateHandler(readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds, TimeUnit.MINUTES));
//                            pipeline.addLast(new TextWebSocketFrameHandler(connectionsCount));
//                            pipeline.addLast(new IMServerHandler(context,connectionsCount));
                            pipeline.addLast(new IMProtoServerHandler(context,connectionsCount));
                        }
                    }) .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(PORT).sync();
            log.info("WebSocket server started on ip {}:{} " , NetworkUtils.getLocalIpAddress(), PORT);
           f.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("WebSocket server start error");
            throw new BusinessException(10001,"WebSocket server start error");
        }finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

}